package mocks

import (
	"bytes"
	"crypto"
	"errors"
	"hash"
	"reflect"

	"blockchain/bccsp"
)

/**
模拟实现的bccsp
@author:lwj
@date:2022.2.22
*/
type MockBCCSP struct {
	//签名key
	SignArgKey bccsp.Key
	//签名参数
	SignDigestArg []byte
	//签名操作
	SignOptsArg bccsp.SignerOpts

	//签名值
	SignValue []byte
	//签名错误
	SignErr error

	//是否验证值
	VerifyValue bool
	//验证值错误
	VerifyErr error

	//期待的签名值
	ExpectedSig []byte

	//import算法中返回的key值
	KeyImportValue bccsp.Key
	//import算法中返回的错误值
	KeyImportErr error

	//加密方法中预定义错误
	EncryptError error
	//加密方法中预定义错误
	DecryptError error

	//预定义hash值
	HashVal []byte
	//预定于hash错误
	HashErr error
}

func (*MockBCCSP) KeyGen(opts bccsp.KeyGenOpts) (bccsp.Key, error) {
	panic("Not yet implemented")
}

func (*MockBCCSP) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (bccsp.Key, error) {
	panic("Not yet implemented")
}

// 直接给定已经存储的值
func (m *MockBCCSP) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (bccsp.Key, error) {
	return m.KeyImportValue, m.KeyImportErr
}

func (*MockBCCSP) GetKey(ski []byte) (bccsp.Key, error) {
	panic("Not yet implemented")
}

// 直接给定存储的hash值
func (m *MockBCCSP) Hash(msg []byte, opts bccsp.HashOpts) ([]byte, error) {
	return m.HashVal, m.HashErr
}

func (*MockBCCSP) GetHash(opts bccsp.HashOpts) (hash.Hash, error) {
	panic("Not yet implemented")
}

//与所产生的3个值均不同则直接返回错误
//否则返回已经设定的值
func (b *MockBCCSP) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) {
	if !reflect.DeepEqual(b.SignArgKey, k) {
		return nil, errors.New("invalid key")
	}
	if !reflect.DeepEqual(b.SignDigestArg, digest) {
		return nil, errors.New("invalid digest")
	}
	if !reflect.DeepEqual(b.SignOptsArg, opts) {
		return nil, errors.New("invalid opts")
	}

	return b.SignValue, b.SignErr
}

func (b *MockBCCSP) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) {
	//如果想检验为成功直接返回成功
	if b.VerifyValue {
		return b.VerifyValue, nil
	}

	// 如果 想要检验未一个错误,直接返回错误
	if b.VerifyErr != nil {
		return b.VerifyValue, b.VerifyErr
	}

	// 否则返回是否和想要设定的预定签名是否相同
	return bytes.Equal(b.ExpectedSig, signature), nil
}

func (m *MockBCCSP) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) {
	if m.EncryptError == nil {
		//直接返回明文值
		return plaintext, nil
	} else {
		//想要返回错误直接返回错误
		return nil, m.EncryptError
	}
}

func (m *MockBCCSP) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) {
	if m.DecryptError == nil {
		//直接返回密文值
		return ciphertext, nil
	} else {
		//想要返回错误直接返回错误
		return nil, m.DecryptError
	}
}

//mock的key值
type MockKey struct {
	//预先定义的秘钥byte
	BytesValue []byte
	//使用bytes时使用的错误
	BytesErr error
	//是否是同田亚平
	Symm bool
	//公钥值
	PK bccsp.Key
	//使用PK方法时候返回的错误
	PKErr error
	//是否是私钥
	Pvt bool
}

func (m *MockKey) Bytes() ([]byte, error) {
	return m.BytesValue, m.BytesErr
}

func (*MockKey) SKI() []byte {
	panic("Not yet implemented")
}

func (m *MockKey) Symmetric() bool {
	return m.Symm
}

func (m *MockKey) Private() bool {
	return m.Pvt
}

func (m *MockKey) PublicKey() (bccsp.Key, error) {
	return m.PK, m.PKErr
}

type SignerOpts struct {
	HashFuncValue crypto.Hash
}

func (o *SignerOpts) HashFunc() crypto.Hash {
	return o.HashFuncValue
}

//mock的 Key产生方法
type KeyGenOpts struct {
	EphemeralValue bool
}

func (*KeyGenOpts) Algorithm() string {
	return "Mock KeyGenOpts"
}

func (o *KeyGenOpts) Ephemeral() bool {
	return o.EphemeralValue
}

//mock的keystore
type KeyStore struct {
	//存储的key值
	GetKeyValue bccsp.Key
	//得到key值报错
	GetKeyErr error
	//存储时候报错
	StoreKeyErr error
}

func (*KeyStore) ReadOnly() bool {
	panic("Not yet implemented")
}

func (ks *KeyStore) GetKey(ski []byte) (bccsp.Key, error) {
	return ks.GetKeyValue, ks.GetKeyErr
}

func (ks *KeyStore) StoreKey(k bccsp.Key) error {
	return ks.StoreKeyErr
}

//mock的keyimport
type KeyImportOpts struct{}

func (*KeyImportOpts) Algorithm() string {
	return "Mock KeyImportOpts"
}

func (*KeyImportOpts) Ephemeral() bool {
	panic("Not yet implemented")
}

//mock的加解密算法
type (
	EncrypterOpts struct{}
	DecrypterOpts struct{}
)

//mock的hash算法操作
type HashOpts struct{}

func (HashOpts) Algorithm() string {
	return "Mock HashOpts"
}

type KeyDerivOpts struct {
	EphemeralValue bool
}

func (*KeyDerivOpts) Algorithm() string {
	return "Mock KeyDerivOpts"
}

func (o *KeyDerivOpts) Ephemeral() bool {
	return o.EphemeralValue
}
